﻿#include "ifkinematicshandle.h"
#include "robotkinematics.h"

#define EPSINON 1e-4  // 精度，小于它就认为是0
#define ALLOW_MAX_DIFF (1 / 180 * pi)  /* 距离上一轴角度的最大允许偏差 */
const double pi = 3.1415926;

IFKinematicsHandle* IFKinematicsHandle::instance = IFKinematicsHandle::getInstance();

IFKinematicsHandle* IFKinematicsHandle::getInstance()
{
    return instance == nullptr ? new IFKinematicsHandle : instance;
}



IFKinematicsHandle::IFKinematicsHandle(): d1(220), a2(380),d4(420), d6(180),
    Joint_MIN(QVector<float>(0)),
    Joint_MAX(QVector<float>(0)),
    theta(QVector<float>(0))
{
    /// Matrix4d::Identity()才是生成单位矩阵, Ones()是生成全是1的矩阵
    tcf = Eigen::Matrix4d::Identity();
}



void IFKinematicsHandle::setRobotParameter(double& d1, double& a2, double& d4, double& d6)
{
    this->d1 = d1;
    this->a2 = a2;
    this->d4 = d4;
    this->d6 = d6;
}



void IFKinematicsHandle::getRobotParameter(double& d1, double& a2, double& d4, double& d6)
{
    d1 = this->d1;
    a2 = this->a2;
    d4 = this->d4;
    d6 = this->d6;
}



void IFKinematicsHandle::getRobotTheta(QVector<float>& theta)
{
    theta.clear();
    theta = this->theta;
}



void IFKinematicsHandle::getRobotJointLimit(QVector<float>& Joint_MIN, QVector<float>& Joint_MAX)
{
    Joint_MIN = this->Joint_MIN;
    Joint_MAX = this->Joint_MAX;
}



std::vector<float> IFKinematicsHandle::getOffsetFromZeroPoint(const JointType& joint)
{
    std::vector<float> offset = {0, 0, 0};

    switch(joint) {
        case BASE:
            offset = {0, 0, 0};
            break;
        case J1:
            offset = {0, 0, d1};
            break;
        case J2:
            offset = {0, 0, d1};
            break;
        case J3:
            offset = {0, 0, d1+a2};
            break;
        case J4:
            offset = {0, 0, d1+a2};
            break;
        case J5:
            offset = {0, 0, d1+a2+d4};
            break;
        case J6:
            offset = {0, 0, d1+a2+d4+d6};
            break;
    }

    return offset;
}


/// parameters : d1 a1 a2 a3 d4 θ1 θ2 θ3 θ4 θ5 θ6 j1 j1 j2 j2 j3 j3 j4 j4 j5 j5 j6 j6 tcfx tcfy tcfz
///      index : 0  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 16 17 18 19 20 21 22 23   24   25
void IFKinematicsHandle::recvParameters(QVector<float> parameters)
{
    if(parameters.size() != 26) return;

    /// 接受dh参数
    this->d1 = parameters[0];
    this->a2 = parameters[1];
    this->d4 = parameters[2];
    this->d6 = parameters[3];

    /// 清空数组 接受θ角
    this->theta.clear();
    for (int i = 0; i < 6; ++i) {

        theta.push_back(parameters[5+i]);

    }

    /// 清空数组 接受各关节极限值
    this->Joint_MIN.clear();
    this->Joint_MAX.clear();
    for (int i = 0; i < 12; i+=2) {

        this->Joint_MIN.push_back(parameters[11+i]);
        this->Joint_MAX.push_back(parameters[11+i+1]);

    }

    this->tcf(0, 3) = parameters[23];
    this->tcf(1, 3) = parameters[24];
    this->tcf(2, 3) = parameters[25];
}




Eigen::Vector3d IFKinematicsHandle::getPositionInWorld(const Joint & joint)
{

    Eigen::Matrix4d world = fKine(joint);

#if 1
    joint.print();
    //qDebug() << QStringLiteral("末端坐标: ") << world(0, 3) << world(1, 3) << world(2, 3);
#endif

    return {world(0, 3), world(1, 3), world(2, 3)};
}


/* 角度值转弧度值 */
static inline double toRadian(double degree)
{
    return (degree / 180.0)* pi ;
}

static inline double toDegree(double radian)
{
    return (radian / pi) * 180.0;
}


/** 获得当前关节值计算出来的工具坐标点在世界坐标下下的坐标
 * @joint 各关节角度
 * @return 4*4位姿矩阵 在世界坐标系下
*/
Eigen::Matrix4d IFKinematicsHandle::fKine(const Joint & joint) const
{

    RobotKinematics hansfkine;
    //Eigen::Matrix4d robot = fKineRobot(joint);
    Eigen::Matrix4d robot = hansfkine.forwardKinematics(joint);     ///正运动学

    /// 因为osg默认世界坐标系原点在0,0,0, 而我们机器人算法的世界坐标系原点在1轴正上方,
    /// 所以有一个d1的偏移量, 需要转换成我们算法坐标系中的坐标位置
    Eigen::Matrix4d robot_2_world;
    robot_2_world << 1, 0, 0, 0,
                    0, 1, 0, 0,
                    0, 0, 1, -220,
                    0, 0, 0, 1;

    /// 旋转矩阵的mapping功能
    /// 将机器人坐标系中的点映射为全局世界坐标系中,用矩阵左乘实现,
    Eigen::Matrix4d world = robot_2_world * (robot * tcf);

    return world;
}



/* 正解函数
* @joint 6轴各关节值结构体，单位角度
* @return 返回一个4*4的位姿矩阵
*/
Eigen::Matrix4d IFKinematicsHandle::fKineRobot(const Joint & joint) const
{

    double j1 = toRadian(joint.j1),
           j2 = toRadian(joint.j2+90),
           j3 = toRadian(joint.j3+90),
           j4 = toRadian(joint.j4),
           j5 = toRadian(joint.j5),
           j6 = toRadian(joint.j6);

    double s1 = sin(j1), c1 = cos(j1),
           s2 = sin(j2), c2 = cos(j2),
           s3 = sin(j3), c3 = cos(j3),
           s4 = sin(j4), c4 = cos(j4),
           s5 = sin(j5), c5 = cos(j5),
           s6 = sin(j6), c6 = cos(j6);

    Eigen::Matrix4d T01, T12, T23, T34, T45, T56, T06;

    T01 << c1,    0,  s1,       0,
           s1,    0, -c1,       0,
            0,    1,   0,      d1,
            0,    0,   0,       1;

    T12 << c2,   s2,   0, a2 * c2,
           s2,  -c2,   0, a2 * s2,
            0,    0,  -1,       0,
            0,    0,   0,       1;

    T23 << c3,    0,  s3,       0,
           s3,    0, -c3,       0,
            0,    1,   0,       0,
            0,    0,   0,       1;

    T34 << c4,    0, -s4,       0,
           s4,    0,  c4,       0,
            0,   -1,   0,      d4,
            0,    0,   0,       1;

    T45 << c5,    0,  s5,       0,
           s5,    0, -c5,       0,
            0,    1,   0,       0,
            0,    0,   0,       1;

    T56 << c6,  -s6,   0,       0,
           s6,   c6,   0,       0,
            0,    0,   1,      d6,
            0,    0,   0,       1;

    T06 = T01 * T12 * T23 * T34 * T45 * T56;
    return T06;
}


Joint IFKinematicsHandle::iKine(const Eigen::Matrix4d & pose)
{
    Joint joint;
    /// 因为osg默认世界坐标系原点在0,0,0, 转换成算法坐标系中的坐标位置
    Eigen::Matrix4d world_2_robot;
    world_2_robot << 1, 0, 0, 0,
                    0, 1, 0, 0,
                    0, 0, 1, 0,
                    0, 0, 0, 1;

    /// 将世界坐标系下的位姿矩阵映射到机器人坐标系下,映射用左乘他们之间的转换矩阵
    Eigen::Matrix4d poseinWorld = world_2_robot * (pose * tcf.inverse());

    joint = iKineRobot(poseinWorld, lastJoint);
    return joint;
}


static void normalize(Eigen::Vector3d& vec)
{

    double n = sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
    vec[0] /= n;
    vec[1] /= n;
    vec[2] /= n;

}


/* 逆解函数
* @Joint 6轴各关节值结构体，单位弧度
* @lastJoints 上一次计算的关节值结构体
* @pose 要解逆解的位姿矩阵
*/
Joint IFKinematicsHandle::iKineRobot(const Eigen::Matrix4d pose, Joint lastjoint)
{
    RobotKinematics kine;
    Joint res = kine.inverseKinematics(pose,lastjoint);
    return res;
}
